using System;
using System.IO;
using System.Net;
using System.Threading;
using Dimebrain.TweetSharp.Core.Caching;

namespace Dimebrain.TweetSharp.Core.Web.Query
{
    partial class WebQueryBase
    {
        protected virtual void ExecuteGetAsync(string url, string prefixKey, IClientCache cache)
        {
            Response = null;

            var client = CreateWebQueryClient();
            var key = CreateCacheKey(prefixKey, url);

            ThreadPool.QueueUserWorkItem(work => ExecuteGetAsyncAndCache(cache, key, url, client));
        }

        protected virtual void ExecuteGetAsync(string url, string prefixKey, IClientCache cache, DateTime absoluteExpiration)
        {
            Response = null;

            var client = CreateWebQueryClient();
            var key = CreateCacheKey(prefixKey, url);

            ThreadPool.QueueUserWorkItem(
                work => ExecuteGetAsyncAndCacheWithExpiry(cache, key, url, absoluteExpiration, client));
        }

        protected virtual void ExecuteGetAsync(string url, string prefixKey, IClientCache cache, TimeSpan slidingExpiration)
        {
            Response = null;

            var client = CreateWebQueryClient();
            var key = CreateCacheKey(prefixKey, url);

            ThreadPool.QueueUserWorkItem(
                work => ExecuteGetAsyncAndCacheWithExpiry(cache, key, url, slidingExpiration, client));
        }

        protected virtual void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            try
            {
                using (var stream = e.Result)
                {
                    using (var reader = new StreamReader(stream))
                    {
                        var result = reader.ReadToEnd();
                        Response = ((IWebQueryClient)sender).Response;

                        if (e.UserState != null)
                        {
                            // no expiration specified
                            if (e.UserState is Pair<IClientCache, string>)
                            {
                                var state = (e.UserState as Pair<IClientCache, string>);
                                state.First.Insert(state.Second, result);
                            }

                            // absolute expiration specified
                            if (e.UserState is Pair<IClientCache, Pair<string, DateTime>>)
                            {
                                var state = e.UserState as Pair<IClientCache, Pair<string, DateTime>>;
                                state.First.Insert(state.Second.First, result, state.Second.Second);
                            }

                            // sliding expiration specified
                            if (e.UserState is Pair<IClientCache, Pair<string, TimeSpan>>)
                            {
                                var state = e.UserState as Pair<IClientCache, Pair<string, TimeSpan>>;
                                state.First.Insert(state.Second.First, result, state.Second.Second);
                            }
                        }

                        // only send query when caching is complete
                        var args = new WebQueryResponseEventArgs(result);
                        OnQueryResponse(args);
                    }
                }
            }
            catch (WebException ex)
            {
                var message = HandleWebException(ex);
                var args = new WebQueryResponseEventArgs(message);

                OnQueryResponse(args);
            }
        }
    }
}